﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Diagnostics;
using System.IO;
using WindowPlace.Common;
using System.Windows;

namespace WindowPlace
{
    /// <summary>
    /// Contains information on a Window
    /// </summary>
    public class WindowInfo : BindableObject
    {
        private bool IsVisible_;
        public bool IsVisible
        {
            get { return IsVisible_; }
            set { IsVisible_ = value; }
        }

        private string Caption_;
        public string Caption
        {
            get { return Caption_; }
            set
            {
                Caption_ = value;
                base.RaisePropertyChanged("Caption");
            }
        }

        public bool IsUseful
        {
            get
            {
                return string.IsNullOrWhiteSpace(this.Caption) == false && this.Width > 0 && this.Height > 0;
            }
        }

        /// <summary>
        /// Allows this Window to be started from WindowPlace
        /// </summary>
        public bool AllowStartup
        {
            get
            {
                return AllowStartup_;
            }
            set
            {
                AllowStartup_ = value;
                base.RaisePropertyChanged("AllowStartup");
            }
        }
        private bool AllowStartup_ = false;

        public string StartupArguments
        {
            get
            {
                return StartupArguments_;
            }
            set
            {
                StartupArguments_ = value;
                base.RaisePropertyChanged("StartupArguments");
            }
        }
        private string StartupArguments_;

        #region hWnd and Window locating (using the CaptionFilter)

        private IntPtr hWnd_;
        [XmlIgnore]
        public IntPtr hWnd
        {
            get { return hWnd_; }
            set { hWnd_ = value; }
        }

        public string ModuleFullFilename
        {
            get
            {
                return ModuleFullFilename_;
            }
            set
            {
                ModuleFullFilename_ = value;
                base.RaisePropertyChanged("ModuleFullFilename");
                base.RaisePropertyChanged("ModuleFilename");
            }
        }
        private string ModuleFullFilename_;

        /// <summary>
        /// Gets the Filename component of ModuleFullFilename
        /// </summary>
        public string ModuleFilename
        {
            get
            {
                return Path.GetFileName(ModuleFullFilename_);
            }
        }

        public string CaptionFilter
        {
            get
            {
                return CaptionFilter_;
            }
            set
            {
                CaptionFilter_ = value;
                base.RaisePropertyChanged("CaptionFilter");
            }
        }
        private string CaptionFilter_;

        public StringFilterTypeEnum CaptionFilterType
        {
            get
            {
                return CaptionFilterType_;
            }
            set
            {
                CaptionFilterType_ = value;
                base.RaisePropertyChanged("CaptionFilterType");
            }
        }
        private StringFilterTypeEnum CaptionFilterType_ = StringFilterTypeEnum.StartsWith;

        private bool CaptionsMatch(string Caption, string CaptionFilter, StringFilterTypeEnum FilterType)
        {
            switch (FilterType)
            {
                case StringFilterTypeEnum.Exact:
                    return Caption.ToUpper() == CaptionFilter.ToUpper();
                case StringFilterTypeEnum.StartsWith:
                    return Caption.ToUpper().StartsWith(CaptionFilter.ToUpper());
                case StringFilterTypeEnum.EndsWith:
                    return Caption.ToUpper().EndsWith(CaptionFilter.ToUpper());
                case StringFilterTypeEnum.Contains:
                    return Caption.ToUpper().Contains(CaptionFilter.ToUpper());
                case StringFilterTypeEnum.Anything:
                    return true;
                default:
                    return Caption.ToUpper() == CaptionFilter.ToUpper();
            }
        }

        public bool FindThisWindow(IEnumerable<WindowInfo> Windows, bool UsehWnd = false)
        {
            Debug.Print("WindowInfo::FindThisWindow called (from {0} Windows)", Windows.Count());
            Debug.Print("  Looking for>'{0}' '{1}' '{2}'", this.hWnd, this.CaptionFilter, this.ModuleFullFilename);
            Windows.ToList().ForEach(a => Debug.Print("     >'{0}' '{1}' '{2}'", a.hWnd, a.Caption, a.ModuleFullFilename));


            if (UsehWnd == false)
            {
                if (Windows.Any(a => CaptionsMatch(a.Caption, this.CaptionFilter_, this.CaptionFilterType_) && a.ModuleFullFilename.ToUpper() == this.ModuleFullFilename.ToUpper()))
                {
                    WindowInfo found = Windows.First(a => CaptionsMatch(a.Caption, this.CaptionFilter_, this.CaptionFilterType_) && a.ModuleFullFilename.ToUpper() == this.ModuleFullFilename.ToUpper());
                    this.hWnd = found.hWnd;
                    this.Caption = found.Caption;
                    IsFound_ = true;
                    base.RaisePropertyChanged("IsFound");
                    base.RaisePropertyChanged("IsNotFound");
                    return true;
                }
                else
                {
                    this.hWnd = IntPtr.Zero;
                    IsFound_ = false;
                    base.RaisePropertyChanged("IsFound");
                    base.RaisePropertyChanged("IsNotFound");
                    return false;
                }
            }
            else
            {
                if (Windows.Any(a => a.hWnd == this.hWnd))
                {
                    WindowInfo found = Windows.First(a => a.hWnd == this.hWnd);
                    this.hWnd = found.hWnd;
                    this.Caption = found.Caption;
                    IsFound_ = true;
                    base.RaisePropertyChanged("IsFound");
                    base.RaisePropertyChanged("IsNotFound");
                    return true;
                }
                else
                {
                    IsFound_ = false;
                    base.RaisePropertyChanged("IsFound");
                    base.RaisePropertyChanged("IsNotFound");
                    return false;
                }
            }
        }

        public void Move(Point Location)
        {
            bool worked = false;
            if (IsFound)
            {
                Top = (int)Location.Y;
                Left = (int)Location.X;
                worked = true;

                Common.Helper.SetWindowRectangle(this.hWnd, this.CurrentRectangle);
                Common.Helper.SetForegroundWindow(this.hWnd);
            }
            else
            {
                Debug.Print("unable to find this window");
                worked = false;
            }
            if (worked == false)
            {
                MessageBox.Show(string.Format("Unable to Move Window '{0}'", this.Caption), "Error", MessageBoxButton.OK);
            }
        }

        public bool IsFound
        {
            get
            {
                return IsFound_;
            }
        }
        private bool IsFound_ = false;

        public bool IsNotFound
        {
            get
            {
                return !IsFound;
            }
        }

        #endregion

        #region Placement and Size

        private bool IgnorePlacementAndSize_;
        public bool IgnorePlacementAndSize
        {
            get { return IgnorePlacementAndSize_; }
            set
            {
                IgnorePlacementAndSize_ = value;
                base.RaisePropertyChanged("IgnorePlacementAndSize");
            }
        }

        public int Top
        {
            get
            {
                return CurrentRectangle_.Top;
            }
            set
            {
                CurrentRectangle_.Bottom = value + Height;
                CurrentRectangle_.Top = value;
            }
        }

        public int Left
        {
            get
            {
                return CurrentRectangle_.Left;
            }
            set
            {
                CurrentRectangle_.Right = value + Width;
                CurrentRectangle_.Left = value;
            }
        }

        public int Width
        {
            get
            {
                return CurrentRectangle_.Right - CurrentRectangle_.Left;
            }
        }

        public int Height
        {
            get
            {
                return CurrentRectangle_.Bottom - CurrentRectangle_.Top;
            }
        }

        public RECT CurrentRectangle
        {
            get
            {
                return CurrentRectangle_;
            }
            set
            {
                this.CurrentRectangle_ = value;
                base.RaisePropertyChanged("CurrentRectangle");
                base.RaisePropertyChanged("Top");
                base.RaisePropertyChanged("Left");
                base.RaisePropertyChanged("Width");
                base.RaisePropertyChanged("Height");
                base.RaisePropertyChanged("LocationString");
                base.RaisePropertyChanged("SizeString");
            }
        }
        private RECT CurrentRectangle_;

        public RECT Rectangle
        {
            get
            {
                return Rectangle_;
            }
            set
            {
                Rectangle_ = value;
            }
        }
        private RECT Rectangle_;

        public string LocationString
        {
            get
            {
                return string.Format("{0}left {1}top", Top, Left);
            }
        }

        public string SizeString
        {
            get
            {
                return string.Format("{0}w {1}h", Width, Height);
            }
        }

        #endregion

        #region Public Methods (some static)

        public override string ToString()
        {
            return string.Format("WindowInfo: {0} (Filter = {1}), Location={2}, Size={3}", this.Caption, this.CaptionFilter, this.LocationString, this.SizeString);
        }

        public static WindowInfo Copy(WindowInfo SourceWindowInfo)
        {
            WindowInfo new_windowinfo = new WindowInfo();
            new_windowinfo.Caption = string.Empty;
            new_windowinfo.CaptionFilter = SourceWindowInfo.CaptionFilter;
            new_windowinfo.CaptionFilterType = SourceWindowInfo.CaptionFilterType;
            new_windowinfo.ModuleFullFilename = SourceWindowInfo.ModuleFullFilename;
            new_windowinfo.CurrentRectangle = new RECT() { Top = SourceWindowInfo.CurrentRectangle.Top, Bottom = SourceWindowInfo.CurrentRectangle.Bottom, Left = SourceWindowInfo.CurrentRectangle.Left, Right = SourceWindowInfo.CurrentRectangle.Right };
            return new_windowinfo;
        }

        #endregion
    }
}
